//------------------------------------------------------------------------------
// <copyright file="RpcBinaryDataImpl.h" company="Microsoft">
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// </copyright>
//------------------------------------------------------------------------------

#pragma once

#include <memory>
#include "RpcBinaryToTextEncoding.h"
#include "RpcCompressionScheme.h"

namespace Microsoft { namespace Internal { namespace GamesTest { namespace Rpc { namespace Server
{
	/// <summary> 
	/// An implementation of the RpcBinaryData class.
	/// </summary>
	class RpcBinaryDataImpl
	{
	public:
		/// <summary> 
		/// Initializes a new instance of the RpcBinaryDataImpl class.
		/// </summary>
		RpcBinaryDataImpl();

		/// <summary> 
		/// Initializes a new instance of the RpcBinaryDataImpl class.
		/// </summary>
		/// <param name="data">The array of data to use.</param>
		/// <param name="dataLength">The size of the data array.</param>
		RpcBinaryDataImpl(std::shared_ptr<unsigned __int8> data, unsigned int dataLength);

		/// <summary> 
		/// Initializes a new instance of the RpcBinaryDataImpl class.  This will create an instance of the RpcBinaryDataImpl
		/// class based on the given existing implementation object.
		/// </summary>
		/// <param name="other">The existing implementation object to be used by the new RpcBinaryDataImpl.</param>
		RpcBinaryDataImpl(const RpcBinaryDataImpl& other);

		/// <summary>
		/// Initializes a new instance of the RpcBinaryDataImpl class.  This will move an existing RpcBinaryData
		/// into a newly created RpcBinaryDataImpl.
		/// </summary>
		/// <param name="other">The existing archive to be moved.</param>
		RpcBinaryDataImpl(RpcBinaryDataImpl&& other);

		/// <summary> 
		/// Initializes a new instance of the RpcBinaryDataImpl class.
		/// This will intialize this class with the given JsonObject.
		/// </summary>
		/// <param name="jsonObject">An existing JsonObject to use as a foundation for this class.</param>
		/// <remarks>The JSON node should be deep-copied because it would be a part of the RpcArchiveImpl DOM tree.</remarks>
		RpcBinaryDataImpl(_In_ const JsonNode& jsonObject);
		
		/// <summary> 
		/// Creates a deep copy of the binary data implementation given by the <paramref name="other"/> parameter.
		/// </summary>
		/// <param name="other">The binary data from which a deep copy shall be created.</param>
		RpcBinaryDataImpl& operator=(const RpcBinaryDataImpl& other);
		
		/// <summary>
		/// Moves an existing RpcBinaryDataImpl to an existing RpcBinaryDataImpl.
		/// </summary>
		/// <param name="other">The existing binary data to be moved.</param>
		RpcBinaryDataImpl& operator=(RpcBinaryDataImpl&& other);
		
		/// <summary>
		/// Serializes this object into a Json object.
		/// </summary>
		JsonNode GetJson();

		/// <summary>
		/// Gets the data that was passed in.
		/// </summary>
		unsigned __int8* GetData()
		{
			return m_data.get();
		}

		/// <summary>
		/// Gets the data that was passed in.
		/// </summary>
		const unsigned __int8* GetData() const
		{
			return m_data.get();
		}
		
		/// <summary>
		/// Gets the length for the binary data.
		/// </summary>
		__declspec(property(get=GetData)) const unsigned __int8* Data;

		/// <summary>
		/// Sets the data that was passed in.
		/// </summary>
		void SetData(std::shared_ptr<unsigned __int8> value, unsigned int length)
		{
			m_data = value;
			m_dataLength = length;
		}

		/// <summary>
		/// Gets the length for the binary data.
		/// </summary>
		unsigned int GetLength()
		{
			return m_dataLength;
		}

		/// <summary>
		/// Gets the length for the binary data.
		/// </summary>
		__declspec(property(get=GetLength)) unsigned int Length;

		/// <summary>
		/// Gets the encoding for the binary data.
		/// </summary>
		RpcBinaryToTextEncoding GetEncoding()
		{
			return m_encoding;
		}

		/// <summary>
		/// Sets the encoding for the binary data.
		/// </summary>
		void SetEncoding(RpcBinaryToTextEncoding encoding)
		{
			m_encoding = encoding;
		}

		/// <summary>
		/// Gets and sets the encoding for the binary data.
		/// </summary>
		__declspec(property(get=GetEncoding, put=SetEncoding)) RpcBinaryToTextEncoding Encoding;
		
		/// <summary>
		/// Gets the compression for the binary data.
		/// </summary>
		RpcCompressionScheme GetCompression()
		{
			return m_compression;
		}
		
		/// <summary>
		/// Sets the compression for the binary data.
		/// </summary>
		void SetCompression(RpcCompressionScheme Compression)
		{
			m_compression = Compression;
		}
		
		/// <summary>
		/// Gets and sets the compression for the binary data.
		/// </summary>
		__declspec(property(get=GetCompression, put=SetCompression)) RpcCompressionScheme Compression;
		
		virtual ~RpcBinaryDataImpl();

	private:
		/// <summary>
		/// Encodes the Data property into a binary to text encoded string.
		/// </summary>
		std::wstring EncodeData();

		/// <summary>
		/// Decodes the encoded data back into binary and sets it to the Data property.
		/// </summary>
		void DecodeData( const JsonString& encodedData);

	private:
		static const wchar_t TypeKey[];
		static const wchar_t CompressionKey[];
		static const wchar_t EncodingKey[];
		static const wchar_t DataKey[];

		RpcBinaryToTextEncoding m_encoding;
		RpcCompressionScheme m_compression;
		std::shared_ptr<unsigned __int8> m_data;
		unsigned int m_dataLength;
	};

}}}}}